import validators from './validators'

class Validator {
    constructor(Vue,{timeout=0}){
        this.result = [];//保存表单内各文本框的校验失败结果，校验成功则为空
        this.timeout = timeout;//提示信息显示时长
        this.listener = {};//存储表单绑定的校验方法，用于点击提交按钮时再次验证，取验证结果
        this.timeoutListener = {};//存储提示信息显示时长定时器，作用是避免错乱清除提示。
        Vue.validator = Vue.prototype.$validator =  this;//把指令赋值给Vue，在vue里面可以自由获取指令信息
    }
    /**
     * 错误信息内容
     * @param {*} message 
     */
    errorTemplate(message){
        return `<div class="example-error" style="font-size: 12px; color: rgb(51, 51, 51); position: absolute; top: -35px; left: 20px;border: 1px solid #ecdede; background-color: rgb(255, 255, 255); padding: 5px 10px; margin: 0px; z-index: 99; box-shadow: rgba(0, 0, 0, 0.12) 0px 2px 4px, rgba(0, 0, 0, 0.04) 0px 0px 6px; border-radius: 4px;">
            <i style="color:red;" class="glyphicon glyphicon-exclamation-sign"></i>
            <b style="position: absolute; left: 4px; bottom: -5px; width: 8px; height: 8px; display: block; border-right: 1px solid rgba(0, 0, 0, 0.1); transform: rotateZ(45deg); border-bottom: 1px solid rgba(0, 0, 0, 0.1); background-color: rgb(255, 255, 255);"></b>
            <span>${message||'对不起，您输入的信息有误'}</span>
        </div>`;
    }
    /**
     * 显示错误信息
     * @param {*} el 绑定的输入框对象
     * @param {*} rule 校验属性
     * @param {*} modelName 输入框的v-model名字 例如：v-model="demo" ，
     * 则名字为demo，用于保存自动清除错误信息的定时器
     */
    showErrorMsg(el,rule,modelName,msg){
        $(el).prev().remove();
        $(el).before(this.errorTemplate(msg?msg:rule.message));
        $('.example-error').off('click').on('click',function(){
            $(this).remove();
        })
        if(this.timeout){
            //判断之前有名字为[modelName]定时器，有的话先把它clear，因为会影响后面的setTimeout
            if(this.timeoutListener[modelName]){
                clearTimeout(this.timeoutListener[modelName]);
            }
            //把定时器储存起来，供后面判断有没有加过[modelName]相同的定时器
            this.timeoutListener[modelName] = setTimeout(()=>{
                $(el).prev().remove();
                $(el).removeClass('validate-error')
            },this.timeout)
        }
        $(el).removeClass('validate-error').addClass('validate-error');
    }
    /**
     * 触发校验方法,参数说明同showErrorMsg方法参数
     * @param {*} el 
     * @param {*} rule 
     * @param {*} modelName 
     */
    fireEvents(el,rule,modelName){
        //根据校验类型 执行相对应的校验方法
        if(validators[rule.type]){
            if(['required','validator'].indexOf(rule.type) === -1 && !el.value){
            }else{
                let result = validators[rule.type](Object.assign(rule,{value:el.value}));
                if(result instanceof Promise){
                    result.then((data)=>{
                        let bool = true;
                        let msg = '';
                        if(typeof(data) == 'object' ){
                            bool = data.success;
                            msg = data.msg;
                        }else {
                            bool = data;
                        }
                        if(!bool){
                            this.showErrorMsg(el,rule,modelName,msg || '')
                            this.result.push(result);
                        }
                    })
                }else if(result instanceof Object){
                    if(!result.success){
                        this.showErrorMsg(el,rule,modelName,result.msg || '')
                        this.result.push(result.success);
                    }
                }
                else{
                    if(!result){
                        this.showErrorMsg(el,rule,modelName)
                        this.result.push(result);
                    }
                }
            }
        }
    }
    /**
     * 绑定控件所有事件,
     * @param {*} el 绑定的输入框对象
     * @param {*} rule 校验属性
     * @param {*} formName 表单名称，用来归类校验控件
     * @param {*} modelName 输入框的v-model名字 例如：v-model="demo" ，
     * 则名字为demo，用于保存自动清除错误信息的定时器
     */
    bindAllEvent(el,binding){
        let rules = binding.value.rule,
            formName = binding.value.form,
            modelName = binding.expression;
        this.result = []
        if (typeof this.listener[formName] === 'undefined') {
            this.listener[formName] = []
        }
        //绑定文本框所有校验事件
        rules.forEach(rule=>{
            const func = ()=>{
                this.fireEvents(el,rule,modelName);
            }
            el.addEventListener(rule.trigger,func);//rule.trigger为事件触发类型
            this.listener[formName].push(func);//储存校验事件
        })
    }
    /**
     * 自动校验当前控件所有校验信息，在文本框v-model更新完之后触发
     * @param {*} el 
     * @param {*} rules 
     * @param {*} modelName 
     */
    verifyAllEvent(el,rules,modelName){
        this.result = [];
        let result = [];
        for(let i=0;i<rules.length;i++) {
            let rule = rules[i];
            if(this.result.length==0){
                if(this.fireEvents(el,rule,modelName) === false){
                    result.push(false);
                    return;
                }else{
                    continue;
                }
            }
            
        }
        return result;
    }
    /**
     * 点击提交按钮时触发formName表单里面所有的校验方法，检测表单是否校验成功，返回true或false
     * true为表单验证通过，false为验证不通过
     * @param {*} formName 
     */
    submit(formName){
        this.result = [];
        return new Promise((resolve,reject)=>{
            if(!this.listener[formName]) resolve(false);
            this.listener[formName].forEach(fn =>{
                fn();
            });
            resolve(this.result.length === 0);
        }).catch(err=>{
            console.error(err)
        });
    }
    /**
     * 安装指令命令
     * @param {*} Vue vue对象用于注册指令
     */
    install(Vue){
        const _self = this;
        Vue.directive('validate',{
            inserted(el,binding,vnode,oldValue){
                _self.bindAllEvent(el,binding);
            },
            update(el,binding,vnode,oldValue){
                //当文本框值改变的时候再次校验
                // if(vnode.data.domProps.value!==oldValue.data.domProps.value){
                //     let rules = binding.value.rule;
                //     const result = _self.verifyAllEvent(el,rules,binding.expression);//校验当前输入框所有校验事件
                //     if(result.length == 0){
                //         $(el).prev().remove();
                //         $(el).removeClass('validate-error');
                //     }
                //     _self.result = [];
                // }
            }
        })
    }
}

export default Validator